﻿using FlowSequencer.Core.FlowElements;
using FlowSequencer.Core.Sequencer;
using FlowSequencer.Model;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Windows.Controls;
using System.Windows.Media;

namespace FlowSequencer.ViewModel
{
    class MachineLineViewModel : INotifyPropertyChanged
    {
        public MachineLineViewModel(int numberOfTasks, int machineNumber)
        {
            IsTwoMachineMode = true;
            NumberOfTasks = numberOfTasks;
            Lines = new ObservableCollection<Lines>();
            Headers = new ObservableCollection<Cell>();
            PopulateTable(numberOfTasks, machineNumber);
        }

        internal void UpdateModel(int numberOfTasks, int machineNumber)
        {
            PopulateTable(numberOfTasks, machineNumber);
        }

        private string TaskSignature = "Z";
        private void PopulateTable(int numberTasks, int numberMachines)
        {
           // var headers = new List<string>() { "Speed", "Abs", "Fuel-1", "Fuel-2", "Fuel-3", "Fuel-4" };
            Lines.Clear();
            Headers.Clear();
            for (int i = 0; i < numberTasks; i++)
            {
                Headers.Add(new Cell()
                {
                    Data = TaskSignature + i.ToString(),
                    Width = 50,
                    Color = Brushes.Blue
                });
            }

            var width = 50;
            var periodList = new ObservableCollection<Cell>() {
                 new Cell() { Data = "20", Index = 0, Width = width, Color = Brushes.Orange },
                 new Cell() { Data = "40", Index = 1, Width = width, Color = Brushes.Orange },
                 new Cell() { Data = "80", Index = 2, Width = width, Color = Brushes.Orange },
                 new Cell() { Data = "80", Index = 3, Width = width, Color = Brushes.Orange },
                 new Cell() { Data = "80", Index = 4, Width = width, Color = Brushes.Orange },
                 new Cell() { Data = "80", Index = 5, Width = width, Color = Brushes.Orange }
            };
            var processingTimeList = new ObservableCollection<Cell>() {
                 new Cell() { Data = "4", Index = 0, Width = width, Color = Brushes.Orange },
                 new Cell() { Data = "10", Index = 1, Width = width, Color = Brushes.Orange },
                 new Cell() { Data = "6", Index = 2, Width = width, Color = Brushes.Orange },
                 new Cell() { Data = "16", Index = 3, Width = width, Color = Brushes.Orange },
                 new Cell() { Data = "6", Index = 4, Width = width, Color = Brushes.Orange },
                 new Cell() { Data = "12", Index = 5, Width = width, Color = Brushes.Orange }
            };
            var realativeDeadlineList = new ObservableCollection<Cell>() {
                 new Cell() { Data = "20", Index = 0, Width = width, Color = Brushes.Orange },
                 new Cell() { Data = "40", Index = 1, Width = width, Color = Brushes.Orange },
                 new Cell() { Data = "80", Index = 2, Width = width, Color = Brushes.Orange },
                 new Cell() { Data = "80", Index = 3, Width = width, Color = Brushes.Orange },
                 new Cell() { Data = "80", Index = 4, Width = width, Color = Brushes.Orange },
                 new Cell() { Data = "80", Index = 5, Width = width, Color = Brushes.Orange }
            };
            var tableData = new List<ObservableCollection<Cell>>() { periodList, processingTimeList, realativeDeadlineList };

            for (int i = 0; i < numberMachines; i++)
            {
                var column = new Lines();
                column.Header = TaskSignature + i.ToString();
                column.ColumnsData = tableData[i];
                //for (int j = 0; j < numberTasks; j++)
                //{
                //    column.ColumnsData.Add(new Cell() { Data = (1 + i * j).ToString(), Index = j, Width = 50, Color = Brushes.Orange });
                //}

                Lines.Add(column);
            }
        }

        public ObservableCollection<Lines> lines;
        public ObservableCollection<Lines> Lines 
        {
            get { return lines; } 
            set 
            {
                if (lines == value) return;
                lines = value;
                NotifyPropertyChanged("Lines");
            }
        }
        public ObservableCollection<Cell> headers;
        public ObservableCollection<Cell> Headers
        {
            get { return headers; }
            set
            {
                headers = value;
                NotifyPropertyChanged("Headers");
            }
        }

        private int numberOfTasks;
        public int NumberOfTasks
        {
            get { return numberOfTasks; }
            set
            {
                if (this.numberOfTasks == value) return;
                this.numberOfTasks = value;
                NotifyPropertyChanged("NumberOfTasks");
            }
        }
        private bool twoMachineMode;
        public bool IsTwoMachineMode
        {
            get { return false; }
            set
            {
                if (this.twoMachineMode == value) return;
                this.twoMachineMode = value;
                NotifyPropertyChanged("TwoMachineMode");
            }
        }

        private List<int> optimalSequencePart;
        public List<int> OptimalSequencePart
        {
            get { return optimalSequencePart; }
            set
            {
                if (this.optimalSequencePart == value) return;
                this.optimalSequencePart = value;
                NotifyPropertyChanged("OptimalSequencePart");
            }
        }
        private int downTime;
        public int DownTime
        {
            get { return downTime; }
            set
            {
                if (this.downTime == value) return;
                this.downTime = value;
                NotifyPropertyChanged("DownTime");
            }
        }
        private string downTimeTaskName;
        public string DownTimeTaskName
        {
            get { return downTimeTaskName; }
            set
            {
                if (this.downTimeTaskName == value) return;
                this.downTimeTaskName = value;
                NotifyPropertyChanged("DownTimeTaskName");
            }
        }

        private int minorCycle;
        public int MinorCycle
        {
            get { return minorCycle; }
            set
            {
                if (this.minorCycle == value) return;
                this.minorCycle = value;
                NotifyPropertyChanged("MinorCycle");
            }
        }
        private int majorCycle;
        public int MajorCycle
        {
            get { return majorCycle; }
            set
            {
                if (this.majorCycle == value) return;
                this.majorCycle = value;
                NotifyPropertyChanged("MajorCycle");
            }
        }


        public Flow GetOptimalSequence()
        {
         //   ISequencer sequencer = new EarliestDueDate(); 
            ISequencer sequencer = new CyclicExecutiveScheduling();
            foreach (var line in Lines)
            {
                var tasks = line.ColumnsData.Select(x => new Task() { Cycles = int.Parse(x.Data), Name = TaskSignature + x.Index.ToString(), Index = x.Index }).ToList<Task>();
                sequencer.InsertLine(new Line() { Tasks = tasks });
            }
            sequencer.ComputeFlow();
            var optimizedFlow = sequencer.GetOptimizedFlow();
            OptimalSequencePart = optimizedFlow.OptimalSequence;
           // DownTime = optimizedFlow.DownTime;
           // DownTimeTaskName = optimizedFlow.DownTimeTaskName;
            MinorCycle = optimizedFlow.MinorCycle;
            MajorCycle = optimizedFlow.MajorCycle;
            return optimizedFlow;
        }

        private void NotifyPropertyChanged(string name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
        public event PropertyChangedEventHandler PropertyChanged;


    }
}
